﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Forms;
using AForge.Imaging;
using AForge.Imaging.Filters;
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Vision.Motion;
using CustomFrameDifferenceDetector = MD.ImageProcessing.CustomFrameDifferenceDetector;

namespace MotionDetection
{
    public partial class MainForm : Form
    {
        private IVideoSource videoSource = null;
        // motion detector
        static MD.ImageProcessing.BlobCountingObjectsProcessing motionProcessing = new MD.ImageProcessing.BlobCountingObjectsProcessing(true);
        MotionDetector detector = new MotionDetector(
            new CustomFrameDifferenceDetector(true),
            motionProcessing);
        // motion detection and processing algorithm
        private int motionDetectionType = 1;
        private int motionProcessingType = 1;

        // statistics length
        private const int statLength = 15;
        // current statistics index
        private int statIndex = 0;
        // ready statistics values
        private int statReady = 0;
        // statistics array
        private int[] statCount = new int[statLength];

        // counter used for flashing
        private int flash = 0;
        private float motionAlarmLevel = 0.015f;

        private List<float> motionHistory = new List<float>();
        private int detectedObjectsCount = -1;

        public MainForm()
        {
            InitializeComponent();
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                // create video source
                FileVideoSource fileSource = new FileVideoSource(openFileDialog.FileName);

                // open it
                OpenVideoSource(fileSource);
            }
        }

        // Open video source
        private void OpenVideoSource(IVideoSource source)
        {
            // set busy cursor
            this.Cursor = Cursors.WaitCursor;

            // close previous video source
            CloseVideoSource();

            // start new video source
            videoSourcePlayer.VideoSource = new AsyncVideoSource(source);
            videoSourcePlayer.Start();

            processedPlayer.VideoSource = new AsyncVideoSource(source);
            processedPlayer.Start();

            // reset statistics
            statIndex = statReady = 0;

            // start timers
            timer.Start();
            alarmTimer.Start();

            videoSource = source;

            this.Cursor = Cursors.Default;
        }

        // Close current video source
        private void CloseVideoSource()
        {
            // set busy cursor
            this.Cursor = Cursors.WaitCursor;

            // stop current video source
            videoSourcePlayer.SignalToStop();
            processedPlayer.SignalToStop();

            // wait 2 seconds until camera stops
            for (int i = 0; (i < 50) && (videoSourcePlayer.IsRunning); i++)
            {
                Thread.Sleep(100);
            }
            if (videoSourcePlayer.IsRunning)
                videoSourcePlayer.Stop();

            // stop timers
            timer.Stop();
            alarmTimer.Stop();

            motionHistory.Clear();

            // reset motion detector
            if (detector != null)
                detector.Reset();

            videoSourcePlayer.BorderColor = Color.Black;
            this.Cursor = Cursors.Default;
        }

        private void videoSourcePlayer_NewFrame(object sender, ref System.Drawing.Bitmap image)
        {
            lock (this)
            {
                if (detector != null)
                {
                    //                    GrayscaleBT709 grayscaleFilter = new GrayscaleBT709();
                    Threshold threshold = new Threshold(95);
                    BitmapData bitmapData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat);
                    var test = new UnmanagedImage(bitmapData);
                    image.UnlockBits(bitmapData);
                    var m = new UnmanagedImage(test.ImageData, test.Width, test.Height, test.Stride, PixelFormat.Format8bppIndexed);
                    m = threshold.Apply(m);

                    float motionLevel = detector.ProcessFrame(image);

                    if (motionLevel > motionAlarmLevel)
                    {
                        // flash for 2 seconds
                        flash = (int)(2 * (1000 / alarmTimer.Interval));
                    }
                    if (motionProcessing.ObjectsCount > 1)
                    {
                        var rects = motionProcessing.ObjectRectangles;
                        detectedObjectsCount = motionProcessing.TrackingCellsCount;
                    }

                    // check objects' count
                    //                    if (detector.MotionProcessingAlgorithm is BlobCountingObjectsProcessing)
                    //                    {
                    //                        try
                    //                        {
                    //                            BlobCountingObjectsProcessing countingDetector = (BlobCountingObjectsProcessing)detector.MotionProcessingAlgorithm;
                    //                            var rects = countingDetector.ObjectRectangles;
                    //                            detectedObjectsCount = countingDetector.ObjectsCount;
                    //                        }
                    //                        catch (Exception)
                    //                        {
                    //                            //                            throw;
                    //                        }
                    //                    }
                    //                    else
                    //                    {
                    //                        detectedObjectsCount = -1;
                    //                    }

                    // accumulate history
                    motionHistory.Add(motionLevel);
                    if (motionHistory.Count > 300)
                    {
                        motionHistory.RemoveAt(0);
                    }

                    //                    if (showMotionHistoryToolStripMenuItem.Checked)
                    //                        DrawMotionHistory(image);
                }
            }
        }

        // On timer event - gather statistics
        private void timer_Tick(object sender, EventArgs e)
        {
            IVideoSource videoSource = videoSourcePlayer.VideoSource;

            if (videoSource != null)
            {
                // get number of frames for the last second
                statCount[statIndex] = videoSource.FramesReceived;

                // increment indexes
                if (++statIndex >= statLength)
                    statIndex = 0;
                if (statReady < statLength)
                    statReady++;

                float fps = 0;

                // calculate average value
                for (int i = 0; i < statReady; i++)
                {
                    fps += statCount[i];
                }
                fps /= statReady;

                statCount[statIndex] = 0;

                lFps.Text = fps.ToString("F2") + " fps";
                lObjectsCount.Text = String.Format("Detected objects Count: {0}", detectedObjectsCount);
            }
        }

        private void alarmTimer_Tick(object sender, EventArgs e)
        {
            if (flash != 0)
            {
                videoSourcePlayer.BorderColor = (flash % 2 == 1) ? Color.Black : Color.Red;
                flash--;
            }
        }

        private void btnStartStop_Click(object sender, EventArgs e)
        {
            if (videoSourcePlayer.IsRunning)
            {
                videoSourcePlayer.SignalToStop();
            }
            else
            {
                videoSourcePlayer.Start();
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
        }

        private void processedPlayer_NewFrame(object sender, ref Bitmap image)
        {
        }
    }
}